home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / yaml.rb < prev   
Text File  |  2008-04-19  |  13KB  |  441 lines

  1. # -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*- vim: sw=4 ts=4
  2. # $Id: yaml.rb 16084 2008-04-19 11:45:39Z knu $
  3. #
  4. # = yaml.rb: top-level module with methods for loading and parsing YAML documents
  5. #
  6. # Author:: why the lucky stiff
  7.  
  8. require 'stringio'
  9. require 'yaml/error'
  10. require 'yaml/syck'
  11. require 'yaml/tag'
  12. require 'yaml/stream'
  13. require 'yaml/constants'
  14.  
  15. # == YAML
  16. #
  17. # YAML(tm) (rhymes with 'camel') is a
  18. # straightforward machine parsable data serialization format designed for
  19. # human readability and interaction with scripting languages such as Perl
  20. # and Python. YAML is optimized for data serialization, formatted
  21. # dumping, configuration files, log files, Internet messaging and
  22. # filtering. This specification describes the YAML information model and
  23. # serialization format. Together with the Unicode standard for characters, it
  24. # provides all the information necessary to understand YAML Version 1.0
  25. # and construct computer programs to process it.
  26. #                         
  27. # See http://yaml.org/ for more information.  For a quick tutorial, please
  28. # visit YAML In Five Minutes (http://yaml.kwiki.org/?YamlInFiveMinutes).
  29. #                              
  30. # == About This Library
  31. #                         
  32. # The YAML 1.0 specification outlines four stages of YAML loading and dumping.
  33. # This library honors all four of those stages, although data is really only
  34. # available to you in three stages.
  35. #     
  36. # The four stages are: native, representation, serialization, and presentation.
  37. #     
  38. # The native stage refers to data which has been loaded completely into Ruby's
  39. # own types. (See +YAML::load+.)
  40. #
  41. # The representation stage means data which has been composed into
  42. # +YAML::BaseNode+ objects.  In this stage, the document is available as a
  43. # tree of node objects.  You can perform YPath queries and transformations
  44. # at this level.  (See +YAML::parse+.)
  45. #   
  46. # The serialization stage happens inside the parser.  The YAML parser used in
  47. # Ruby is called Syck.  Serialized nodes are available in the extension as
  48. # SyckNode structs.
  49. #       
  50. # The presentation stage is the YAML document itself.  This is accessible
  51. # to you as a string.  (See +YAML::dump+.)
  52. #   
  53. # For more information about the various information models, see Chapter
  54. # 3 of the YAML 1.0 Specification (http://yaml.org/spec/#id2491269).
  55. #
  56. # The YAML module provides quick access to the most common loading (YAML::load)
  57. # and dumping (YAML::dump) tasks.  This module also provides an API for registering
  58. # global types (YAML::add_domain_type).
  59. #
  60. # == Example
  61. #
  62. # A simple round-trip (load and dump) of an object.
  63. #
  64. #     require "yaml"
  65. #
  66. #     test_obj = ["dogs", "cats", "badgers"]
  67. #
  68. #     yaml_obj = YAML::dump( test_obj )
  69. #                         # -> ---
  70. #                              - dogs
  71. #                              - cats
  72. #                              - badgers
  73. #     ruby_obj = YAML::load( yaml_obj )
  74. #                         # => ["dogs", "cats", "badgers"]
  75. #     ruby_obj == test_obj
  76. #                         # => true
  77. #
  78. # To register your custom types with the global resolver, use +add_domain_type+.
  79. #
  80. #     YAML::add_domain_type( "your-site.com,2004", "widget" ) do |type, val|
  81. #         Widget.new( val )
  82. #     end
  83. #
  84. module YAML
  85.  
  86.     Resolver = YAML::Syck::Resolver
  87.     DefaultResolver = YAML::Syck::DefaultResolver
  88.     DefaultResolver.use_types_at( @@tagged_classes )
  89.     GenericResolver = YAML::Syck::GenericResolver
  90.     Parser = YAML::Syck::Parser
  91.     Emitter = YAML::Syck::Emitter
  92.  
  93.     # Returns a new default parser
  94.     def YAML.parser; Parser.new.set_resolver( YAML.resolver ); end
  95.     # Returns a new generic parser
  96.     def YAML.generic_parser; Parser.new.set_resolver( GenericResolver ); end
  97.     # Returns the default resolver
  98.     def YAML.resolver; DefaultResolver; end
  99.     # Returns a new default emitter
  100.     def YAML.emitter; Emitter.new.set_resolver( YAML.resolver ); end
  101.  
  102.     #
  103.     # Converts _obj_ to YAML and writes the YAML result to _io_.
  104.     #     
  105.     #   File.open( 'animals.yaml', 'w' ) do |out|
  106.     #     YAML.dump( ['badger', 'elephant', 'tiger'], out )
  107.     #   end
  108.     #
  109.     # If no _io_ is provided, a string containing the dumped YAML
  110.     # is returned.
  111.     #
  112.     #   YAML.dump( :locked )
  113.     #      #=> "--- :locked"
  114.     #
  115.     def YAML.dump( obj, io = nil )
  116.         obj.to_yaml( io || io2 = StringIO.new )
  117.         io || ( io2.rewind; io2.read )
  118.     end
  119.  
  120.     #
  121.     # Load a document from the current _io_ stream.
  122.     #
  123.     #   File.open( 'animals.yaml' ) { |yf| YAML::load( yf ) }
  124.     #      #=> ['badger', 'elephant', 'tiger']
  125.     #
  126.     # Can also load from a string.
  127.     #
  128.     #   YAML.load( "--- :locked" )
  129.     #      #=> :locked
  130.     #
  131.     def YAML.load( io )
  132.         yp = parser.load( io )
  133.     end
  134.  
  135.     #
  136.     # Load a document from the file located at _filepath_.
  137.     #
  138.     #   YAML.load_file( 'animals.yaml' )
  139.     #      #=> ['badger', 'elephant', 'tiger']
  140.     #
  141.     def YAML.load_file( filepath )
  142.         File.open( filepath ) do |f|
  143.             load( f )
  144.         end
  145.     end
  146.  
  147.     #
  148.     # Parse the first document from the current _io_ stream
  149.     #
  150.     #   File.open( 'animals.yaml' ) { |yf| YAML::load( yf ) }
  151.     #      #=> #<YAML::Syck::Node:0x82ccce0
  152.     #           @kind=:seq,
  153.     #           @value=
  154.     #            [#<YAML::Syck::Node:0x82ccd94
  155.     #              @kind=:scalar,
  156.     #              @type_id="str",
  157.     #              @value="badger">,
  158.     #             #<YAML::Syck::Node:0x82ccd58
  159.     #              @kind=:scalar,
  160.     #              @type_id="str",
  161.     #              @value="elephant">,
  162.     #             #<YAML::Syck::Node:0x82ccd1c
  163.     #              @kind=:scalar,
  164.     #              @type_id="str",
  165.     #              @value="tiger">]>
  166.     #
  167.     # Can also load from a string.
  168.     #
  169.     #   YAML.parse( "--- :locked" )
  170.     #      #=> #<YAML::Syck::Node:0x82edddc 
  171.     #            @type_id="tag:ruby.yaml.org,2002:sym", 
  172.     #            @value=":locked", @kind=:scalar>
  173.     #
  174.     def YAML.parse( io )
  175.         yp = generic_parser.load( io )
  176.     end
  177.  
  178.     #
  179.     # Parse a document from the file located at _filepath_.
  180.     #
  181.     #   YAML.parse_file( 'animals.yaml' )
  182.     #      #=> #<YAML::Syck::Node:0x82ccce0
  183.     #           @kind=:seq,
  184.     #           @value=
  185.     #            [#<YAML::Syck::Node:0x82ccd94
  186.     #              @kind=:scalar,
  187.     #              @type_id="str",
  188.     #              @value="badger">,
  189.     #             #<YAML::Syck::Node:0x82ccd58
  190.     #              @kind=:scalar,
  191.     #              @type_id="str",
  192.     #              @value="elephant">,
  193.     #             #<YAML::Syck::Node:0x82ccd1c
  194.     #              @kind=:scalar,
  195.     #              @type_id="str",
  196.     #              @value="tiger">]>
  197.     #
  198.     def YAML.parse_file( filepath )
  199.         File.open( filepath ) do |f|
  200.             parse( f )
  201.         end
  202.     end
  203.  
  204.     #
  205.     # Calls _block_ with each consecutive document in the YAML
  206.     # stream contained in _io_.
  207.     #
  208.     #   File.open( 'many-docs.yaml' ) do |yf|
  209.     #     YAML.each_document( yf ) do |ydoc|
  210.     #       ## ydoc contains the single object
  211.     #       ## from the YAML document
  212.     #     end
  213.     #   end
  214.     #
  215.     def YAML.each_document( io, &block )
  216.         yp = parser.load_documents( io, &block )
  217.     end
  218.  
  219.     #
  220.     # Calls _block_ with each consecutive document in the YAML
  221.     # stream contained in _io_.
  222.     #
  223.     #   File.open( 'many-docs.yaml' ) do |yf|
  224.     #     YAML.load_documents( yf ) do |ydoc|
  225.     #       ## ydoc contains the single object
  226.     #       ## from the YAML document
  227.     #     end
  228.     #   end
  229.     #
  230.     def YAML.load_documents( io, &doc_proc )
  231.         YAML.each_document( io, &doc_proc )
  232.     end
  233.  
  234.     #
  235.     # Calls _block_ with a tree of +YAML::BaseNodes+, one tree for
  236.     # each consecutive document in the YAML stream contained in _io_.
  237.     #
  238.     #   File.open( 'many-docs.yaml' ) do |yf|
  239.     #     YAML.each_node( yf ) do |ydoc|
  240.     #       ## ydoc contains a tree of nodes
  241.     #       ## from the YAML document
  242.     #     end
  243.     #   end
  244.     #
  245.     def YAML.each_node( io, &doc_proc )
  246.         yp = generic_parser.load_documents( io, &doc_proc )
  247.     end
  248.  
  249.     #
  250.     # Calls _block_ with a tree of +YAML::BaseNodes+, one tree for
  251.     # each consecutive document in the YAML stream contained in _io_.
  252.     #
  253.     #   File.open( 'many-docs.yaml' ) do |yf|
  254.     #     YAML.parse_documents( yf ) do |ydoc|
  255.     #       ## ydoc contains a tree of nodes
  256.     #       ## from the YAML document
  257.     #     end
  258.     #   end
  259.     #
  260.     def YAML.parse_documents( io, &doc_proc )
  261.         YAML.each_node( io, &doc_proc )
  262.     end
  263.  
  264.     #
  265.     # Loads all documents from the current _io_ stream, 
  266.     # returning a +YAML::Stream+ object containing all
  267.     # loaded documents.
  268.     #
  269.     def YAML.load_stream( io )
  270.         d = nil
  271.         parser.load_documents( io ) do |doc|
  272.             d = YAML::Stream.new if not d
  273.             d.add( doc ) 
  274.         end
  275.         return d
  276.     end
  277.  
  278.     #
  279.     # Returns a YAML stream containing each of the items in +objs+,
  280.     # each having their own document.
  281.     #
  282.     #   YAML.dump_stream( 0, [], {} )
  283.     #     #=> --- 0
  284.     #         --- []
  285.     #         --- {}
  286.     #
  287.     def YAML.dump_stream( *objs )
  288.         d = YAML::Stream.new
  289.         objs.each do |doc|
  290.             d.add( doc ) 
  291.         end
  292.         d.emit
  293.     end
  294.  
  295.     #
  296.     # Add a global handler for a YAML domain type.
  297.     #
  298.     def YAML.add_domain_type( domain, type_tag, &transfer_proc )
  299.         resolver.add_type( "tag:#{ domain }:#{ type_tag }", transfer_proc )
  300.     end
  301.  
  302.     #
  303.     # Add a transfer method for a builtin type
  304.     #
  305.     def YAML.add_builtin_type( type_tag, &transfer_proc )
  306.         resolver.add_type( "tag:yaml.org,2002:#{ type_tag }", transfer_proc )
  307.     end
  308.  
  309.     #
  310.     # Add a transfer method for a builtin type
  311.     #
  312.     def YAML.add_ruby_type( type_tag, &transfer_proc )
  313.         resolver.add_type( "tag:ruby.yaml.org,2002:#{ type_tag }", transfer_proc )
  314.     end
  315.  
  316.     #
  317.     # Add a private document type
  318.     #
  319.     def YAML.add_private_type( type_re, &transfer_proc )
  320.         resolver.add_type( "x-private:" + type_re, transfer_proc )
  321.     end
  322.  
  323.     #
  324.     # Detect typing of a string
  325.     #
  326.     def YAML.detect_implicit( val )
  327.         resolver.detect_implicit( val )
  328.     end
  329.  
  330.     #
  331.     # Convert a type_id to a taguri
  332.     #
  333.     def YAML.tagurize( val )
  334.         resolver.tagurize( val )
  335.     end
  336.  
  337.     #
  338.     # Apply a transfer method to a Ruby object
  339.     #
  340.     def YAML.transfer( type_id, obj )
  341.         resolver.transfer( YAML.tagurize( type_id ), obj )
  342.     end
  343.  
  344.     #
  345.     # Apply any implicit a node may qualify for
  346.     #
  347.     def YAML.try_implicit( obj )
  348.         YAML.transfer( YAML.detect_implicit( obj ), obj )
  349.     end
  350.  
  351.     #
  352.     # Method to extract colon-seperated type and class, returning
  353.     # the type and the constant of the class
  354.     #
  355.     def YAML.read_type_class( type, obj_class )
  356.         scheme, domain, type, tclass = type.split( ':', 4 )
  357.         tclass.split( "::" ).each { |c| obj_class = obj_class.const_get( c ) } if tclass
  358.         return [ type, obj_class ]
  359.     end
  360.  
  361.     #
  362.     # Allocate blank object
  363.     #
  364.     def YAML.object_maker( obj_class, val )
  365.         if Hash === val
  366.             o = obj_class.allocate
  367.             val.each_pair { |k,v|
  368.                 o.instance_variable_set("@#{k}", v)
  369.             }
  370.             o
  371.         else
  372.             raise YAML::Error, "Invalid object explicitly tagged !ruby/Object: " + val.inspect
  373.         end
  374.     end
  375.  
  376.     #
  377.     # Allocate an Emitter if needed
  378.     #
  379.     def YAML.quick_emit( oid, opts = {}, &e )
  380.         out = 
  381.             if opts.is_a? YAML::Emitter
  382.                 opts
  383.             else
  384.                 emitter.reset( opts )
  385.             end
  386.         oid =
  387.             case oid when Fixnum, NilClass; oid
  388.             else oid = "#{oid.object_id}-#{oid.hash}"
  389.             end
  390.         out.emit( oid, &e )
  391.     end
  392.     
  393. end
  394.  
  395. require 'yaml/rubytypes'
  396. require 'yaml/types'
  397.  
  398. module Kernel
  399.     #
  400.     # ryan:: You know how Kernel.p is a really convenient way to dump ruby
  401.     #        structures?  The only downside is that it's not as legible as
  402.     #        YAML.
  403.     #
  404.     # _why:: (listening)
  405.     #
  406.     # ryan:: I know you don't want to urinate all over your users' namespaces.
  407.     #        But, on the other hand, convenience of dumping for debugging is,
  408.     #        IMO, a big YAML use case.
  409.     #
  410.     # _why:: Go nuts!  Have a pony parade!
  411.     #
  412.     # ryan:: Either way, I certainly will have a pony parade.
  413.     #
  414.  
  415.     # Prints any supplied _objects_ out in YAML.  Intended as
  416.     # a variation on +Kernel::p+.
  417.     #
  418.     #   S = Struct.new(:name, :state)
  419.     #   s = S['dave', 'TX']
  420.     #   y s
  421.     #
  422.     # _produces:_
  423.     #
  424.     #   --- !ruby/struct:S 
  425.     #   name: dave
  426.     #   state: TX
  427.     #
  428.     def y( object, *objects )
  429.         objects.unshift object
  430.         puts( if objects.length == 1
  431.                   YAML::dump( *objects )
  432.               else
  433.                   YAML::dump_stream( *objects )
  434.               end )
  435.     end
  436.     private :y
  437. end
  438.  
  439.  
  440.